/*
 * Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2019. All rights reserved.
 * Description: video analysis adas implementation
 * Author: HiMobileCam Reference Develop Team
 * Create: 2019-11-01
 */

#include "hi_video_analysis_adas.h"
#include "hi_eventhub.h"
#include "hi_message.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */

#define VIDEOANALYSIS_ADAS_RETURN_IF_NOT_INIT()        \
    do{                                                \
        HI_MUTEX_LOCK(g_adasCtx.initMutex);            \
        if (g_adasCtx.isInitialized != HI_TRUE) {      \
            HI_MUTEX_UNLOCK(g_adasCtx.initMutex);      \
            MLOGW("not inited, please init first\n");  \
            return HI_VIDEOANALYSIS_ADAS_ENOINIT;      \
        }                                              \
        HI_MUTEX_UNLOCK(g_adasCtx.initMutex);          \
    } while (0)

typedef struct {
    HiAiserviceAdasHandle algHdl;
    HI_HANDLE taskHdl;
    HI_BOOL isUsed;
    HI_BOOL isCalibrated;
    HI_VIDEOANALYSIS_AdasTaskResultProcCb resultCb;
} VIDEOANALYSIS_AdasTaskCtx;

typedef struct {
    pthread_mutex_t initMutex;
    HI_BOOL isInitialized;
    pthread_mutex_t taskCtxMutex;
    VIDEOANALYSIS_AdasTaskCtx adasTaskCtx[HI_VIDEOANALYSIS_ADAS_TASK_NUM_MAX];
}VIDEOANALYSIS_AdasCtx;

VIDEOANALYSIS_AdasCtx g_adasCtx = {
    .isInitialized = HI_FALSE,
    .initMutex = PTHREAD_MUTEX_INITIALIZER,
};

static HI_FLOAT g_adasAlgSpeed = 40.0;
static HI_U32 g_adasAlgDayNight = 1;

static HI_FLOAT  VIDEOANALYSIS_AdasGetSpeed(HI_VOID)
{
    /* implementation by call real function */
    return g_adasAlgSpeed;
}

static HI_FLOAT  VIDEOANALYSIS_AdasGetDayNight(HI_VOID)
{
    /* implementation by call real function */
    return g_adasAlgDayNight;
}

static HI_S32 VIDEOANALYSIS_GetTaskHdl(const VIDEOANALYSIS_AdasCtx *adasCtx, HI_HANDLE *taskHdl)
{
    HI_S32 i;
    for (i = 0; i < HI_VIDEOANALYSIS_ADAS_TASK_NUM_MAX; i++) {
        if (adasCtx->adasTaskCtx[i].isUsed == HI_FALSE) {
            break;
        }
    }

    if (i == HI_VIDEOANALYSIS_ADAS_TASK_NUM_MAX) {
        MLOGE("task reach max number(%d)\n", HI_VIDEOANALYSIS_ADAS_TASK_NUM_MAX);
        return HI_FAILURE;
    }

    *taskHdl = i;
    return HI_SUCCESS;
}

static HI_S32 VIDEOANALYSIS_GetTaskHdlByadasAlgHdl(const VIDEOANALYSIS_AdasCtx *adasCtx, HiAiserviceAdasHandle algHdl,
    HI_HANDLE *taskHdl)
{
    HI_S32 i;
    for (i = 0; i < HI_VIDEOANALYSIS_ADAS_TASK_NUM_MAX; i++) {
        if (adasCtx->adasTaskCtx[i].isUsed == HI_TRUE && adasCtx->adasTaskCtx[i].algHdl == algHdl) {
            break;
        }
    }

    if (i == HI_VIDEOANALYSIS_ADAS_TASK_NUM_MAX) {
        return HI_FAILURE;
    }

    *taskHdl = i;
    return HI_SUCCESS;
}

static HI_VOID* VIDEOANALYSIS_AdasAlgoMemAlloc(HI_U32 bufSize, HiAdasAlgoMMZInfo *mmzInfo)
{
    if (bufSize == 0) {
        MLOGE("bufSize(%d) err\n", bufSize);
        return HI_NULL;
    }

    HI_VOID* virualAddrPtr = malloc(bufSize);
    return virualAddrPtr;
}

static HI_S32 VIDEOANALYSIS_AdasAlgoMemFlush(HI_VOID *virtualAddr, HI_U64 phyAddr, HI_U32 mmzBufSize)
{
    if (virtualAddr == HI_NULL) {
        MLOGE("param err\n");
        return HI_FAILURE;
    }

    return HI_SUCCESS;
}

static HI_S32 VIDEOANALYSIS_AdasAlgoMemFree(HI_VOID *virtualAddr, HI_U64 phyAddr)
{
    if (virtualAddr == HI_NULL) {
        MLOGE("virtualAddr null err\n");
        return HI_FAILURE;
    }

    free(virtualAddr);
    return HI_SUCCESS;
}

static HI_S32 VIDEOANALYSIS_AdasPublishEvent(HI_EVENT_ID eventId, HI_S32 result, HI_CHAR *payload, HI_U32 length)
{
    HI_EVENT_S event;
    memset(&event, 0, sizeof(HI_EVENT_S));
    event.EventID = eventId;
    event.s32Result = result;

    HI_S32 ret;
    if (payload != HI_NULL) {
        ret = memcpy_s(&event.aszPayload, EVENT_PAYLOAD_LEN, payload, length);
        if (ret != EOK) {
            MLOGE("memcpy_s failed\n");
            return HI_FAILURE;
        }
    }

    ret = HI_EVTHUB_Publish(&event);
    if (ret != HI_SUCCESS) {
        MLOGE("pulblish event(0x%08X) failed(0x%08X)\n", event.EventID, ret);
        return HI_FAILURE;
    }

    return HI_SUCCESS;
}

static HI_VOID VIDEOANALYSIS_AdasCalibrateCallback(HiAiserviceAdasHandle adas, HI_S32 result,
    HiAdasCalibrateResult* caliResult)
{
    MLOGI("calibration(%d, %d) completed\n", caliResult->vanishPoint.x, caliResult->vanishPoint.y);
    HI_HANDLE adasTaskHdl;
    HI_S32 ret = VIDEOANALYSIS_GetTaskHdlByadasAlgHdl(&g_adasCtx, adas, &adasTaskHdl);
    if (ret == HI_SUCCESS) {
        VIDEOANALYSIS_AdasTaskCtx *adasTaskCtx = &g_adasCtx.adasTaskCtx[adasTaskHdl];
        if (result == HI_SUCCESS) {
            adasTaskCtx->isCalibrated = HI_TRUE;

            HI_CHAR payload[8]; /* payload size 8 bytes */
            HI_U32 length = 8; /* payload size 8 bytes */
            memcpy(payload, &caliResult->vanishPoint.x, sizeof(HI_U32));
            memcpy((payload + 4), &caliResult->vanishPoint.y, sizeof(HI_U32)); /* the second param write at addr 4 */
            (HI_VOID)VIDEOANALYSIS_AdasPublishEvent(HI_EVENT_VIDEOANALYSIS_ADAS_CALIBRATION, adasTaskCtx->isCalibrated,
                payload, length);
        }
    }
    return;
}

static HI_VOID VIDEOANALYSIS_AdasEventCallback(HiAiserviceAdasHandle adas, HiAdasEventType eventType,
    const HiAdasEventData* dataInfo)
{
    switch (eventType) {
        case HI_ADAS_EVENT_RESULT_PER_IMAGE:
            MLOGD("HI_ADAS_EVENT_RESULT_PER_IMAGE\n");
            (HI_VOID)VIDEOANALYSIS_AdasPublishEvent(HI_EVENT_VIDEOANALYSIS_ADAS_RESULT_PER_IMAGE, 0, HI_NULL, 0);
            break;
        case HI_ADAS_EVENT_ERROR:
            MLOGD("HI_ADAS_EVENT_ERROR\n");
            (HI_VOID)VIDEOANALYSIS_AdasPublishEvent(HI_EVENT_VIDEOANALYSIS_ADAS_ERROR, 0, HI_NULL, 0);
            break;
        default:
            MLOGE("not support ai service event[%d]\n", eventType);
    }
    return;
}

static HI_S32 VIDEOANALYSIS_AdasVideoProcessUpdateAttr(VIDEOANALYSIS_AdasTaskCtx *adasTaskCtx)
{
    /* update speed if necessary */
    static HI_FLOAT speed = 0;
    HI_FLOAT speedTmp = VIDEOANALYSIS_AdasGetSpeed();
    if (speed != speedTmp) {
        HiAdasCmdPara cmdPara;
        cmdPara.len = sizeof(speedTmp);
        HI_S32 ret = memcpy_s(&cmdPara.data, HI_ADAS_INVOKE_BYTE_NUM, &speedTmp, cmdPara.len);
        if (ret != EOK) {
            MLOGE("memcpy_s err\n");
            return HI_FAILURE;
        }

        ret = HI_AISERVICE_ADAS_Invoke(adasTaskCtx->algHdl,
            HI_VIDEOANALYSIS_ADAS_CMD_SET_SPEED, (const HiAdasCmdPara*)&cmdPara);
        if (ret != HI_SUCCESS) {
            MLOGE("HI_AISERVICE_ADAS_Invoke set speed failed(%d)\n", ret);
            return HI_FAILURE;
        }
        speed = speedTmp;
    }

    /* update daynight if necessary */
    static HI_U32 dayNight = 0; /* 0: night, 1: day */
    HI_U32 dayNightTmp = VIDEOANALYSIS_AdasGetDayNight();
    if (dayNight != dayNightTmp) {
        HiAdasCmdPara cmdPara;
        cmdPara.len = sizeof(dayNightTmp);
        HI_S32 ret = memcpy_s(&cmdPara.data, HI_ADAS_INVOKE_BYTE_NUM, &dayNightTmp, cmdPara.len);
        if (ret != EOK) {
            MLOGE("memcpy_s err\n");
            return HI_FAILURE;
        }

        ret = HI_AISERVICE_ADAS_Invoke(adasTaskCtx->algHdl,
            HI_VIDEOANALYSIS_ADAS_CMD_SET_DAY_NIGHT, (const HiAdasCmdPara*)&cmdPara);
        if (ret != HI_SUCCESS) {
            MLOGE("HI_AISERVICE_ADAS_Invoke set daynight failed(%d)\n", ret);
            return HI_FAILURE;
        }
        dayNight = dayNightTmp;
    }

    return HI_SUCCESS;
}

static HI_S32 VIDEOANALYSIS_AdasVideoProcessTaskCb(HI_MAPI_FRAME_DATA_S *algData, HI_VOID *privData)
{
    MLOGD(YELLOW"current process, data(%d x %d), pts(%lld)"NONE"\n",
            algData->u32Width, algData->u32Height, algData->u64pts);
    VIDEOANALYSIS_AdasTaskCtx *adasTaskCtx = (VIDEOANALYSIS_AdasTaskCtx *)privData;

    HiAdasImage image;
    memset(&image, 0, sizeof(HiAdasImage));
    image.height    = algData->u32Height;
    image.imageType = algData->enPixelFormat;
    image.imgUid    = algData->u64pts;
    image.phyAddr   = algData->u64PhyAddr[0];
    image.stride    = algData->u32Stride[0];
    image.virAddr   = algData->u64VirAddr[0];
    image.width     = algData->u32Width;

    switch (algData->enPixelFormat) {
        case PIXEL_FORMAT_YVU_SEMIPLANAR_420:
            image.imageType = HI_AIENGINE_IMAGE_TYPE_YVU420SP;
            break;
        default:
            MLOGW("pix format(%d) not supprot currently\n", algData->enPixelFormat);
            return HI_FAILURE;
    }

    HI_S32 ret = VIDEOANALYSIS_AdasVideoProcessUpdateAttr(adasTaskCtx);
    if (ret != HI_SUCCESS) {
        MLOGE("update attr failed(%d), continue\n", ret);
        return HI_FAILURE;
    }

    HiAdasAlgoProcessResult aiServiceResult;
    memset(&aiServiceResult, 0, sizeof(HiAdasAlgoProcessResult));
    ret = HI_AISERVICE_ADAS_ProcessImage(adasTaskCtx->algHdl, (const HiAdasImage*)&image, &aiServiceResult);
    if (ret != HI_SUCCESS) {
        MLOGE("HI_AISERVICE_ADAS_ProcessImage failed(%d), continue\n", ret);
        return HI_FAILURE;
    }

    HI_VIDEOANALYSIS_AdasResult adasResult;
    memcpy(&adasResult.result, &aiServiceResult, sizeof(HiAdasAlgoProcessResult));
    adasResult.width  = image.width;
    adasResult.height = image.height;

    /* adas task result process callback */
    if (adasTaskCtx->resultCb != HI_NULL && adasTaskCtx->isCalibrated == HI_TRUE) {
        MLOGD("call pdt result prc callback\n");
        adasTaskCtx->resultCb(&adasResult, adasTaskCtx->algHdl);
    }

    return HI_SUCCESS;
}

static HI_VOID VIDEOANALYSIS_AdasGenerateVideoProcessTaskCfg(
    VIDEOANALYSIS_AdasTaskCtx *adasTaskCtx,
    const HI_VIDEOANALYSIS_AdasVideoProcessTaskCfg *adasVideoProcessTaskCfg,
    HI_VIDEOPROCESS_TaskCfg *videoProcessTaskCfg)
{
    videoProcessTaskCfg->algCnt = 1;
    videoProcessTaskCfg->bufDepth = 1;
    videoProcessTaskCfg->frameRate = adasVideoProcessTaskCfg->frameRate;
    memcpy(&videoProcessTaskCfg->yuvSrc, &adasVideoProcessTaskCfg->yuvSrc, sizeof(HI_VIDEOPROCESS_YuvSrc));

    videoProcessTaskCfg->algAttr[0].algType = HI_VIDEOPROCESS_ALG_TYPE_ADAS;
    videoProcessTaskCfg->algAttr[0].taskCbSet.taskCb = VIDEOANALYSIS_AdasVideoProcessTaskCb;
    videoProcessTaskCfg->algAttr[0].taskCbSet.privData = adasTaskCtx;
}

HI_S32 HI_VIDEOANALYSIS_InitAdasService(HI_VOID)
{
    HI_MUTEX_LOCK(g_adasCtx.initMutex);

    if (g_adasCtx.isInitialized == HI_TRUE) {
        MLOGW("adas service has already been init!\n");
        HI_MUTEX_UNLOCK(g_adasCtx.initMutex);
        return HI_SUCCESS;
    }

    MLOGD("init adas service\n");
    HI_S32 ret = HI_AISERVICE_ADAS_Init();
    if (ret != HI_SUCCESS) {
        HI_MUTEX_UNLOCK(g_adasCtx.initMutex);
        MLOGE("HI_AISERVICE_ADAS_Init failed(%d)\n", ret);
        return HI_FAILURE;
    }

    MLOGD("init video process\n");
    ret = HI_VIDEOPROCESS_Init();
    if (ret != HI_SUCCESS && ret != HI_VIDEOPROCESS_EINITIALIZED) {
        HI_MUTEX_UNLOCK(g_adasCtx.initMutex);
        MLOGE("HI_VIDEOANALYSIS_InitVideoProcess failed(%d)\n", ret);
        return HI_FAILURE;
    }

    HI_MUTEX_INIT_LOCK(g_adasCtx.taskCtxMutex);

    g_adasCtx.isInitialized = HI_TRUE;
    HI_MUTEX_UNLOCK(g_adasCtx.initMutex);
    return HI_SUCCESS;
}

HI_S32 HI_VIDEOANALYSIS_RegisteAdasAlg(const HiAdasAlgorithm *algorithm)
{
    HI_APPCOMM_CHECK_POINTER(algorithm, HI_VIDEOANALYSIS_ADAS_EINVAL);
    VIDEOANALYSIS_ADAS_RETURN_IF_NOT_INIT();

    HI_S32 ret = HI_AISERVICE_ADAS_Register(algorithm);
    if (ret != HI_SUCCESS) {
        MLOGE("HI_AISERVICE_ADAS_Register failed(%d)\n", ret);
        return HI_FAILURE;
    }

    return HI_SUCCESS;
}

HI_S32 HI_VIDEOANALYSIS_UnregisteAdasAlg(const HI_CHAR *adasAlgoName)
{
    HI_APPCOMM_CHECK_POINTER(adasAlgoName, HI_VIDEOANALYSIS_ADAS_EINVAL);
    VIDEOANALYSIS_ADAS_RETURN_IF_NOT_INIT();

    HI_S32 ret = HI_AISERVICE_ADAS_Unregister(adasAlgoName);
    if (ret != HI_SUCCESS) {
        MLOGE("HI_AISERVICE_ADAS_Unregister failed(%d)\n", ret);
        return HI_FAILURE;
    }

    return HI_SUCCESS;
}

HI_S32 HI_VIDEOANALYSIS_GetAdasAlgCapability(const HI_CHAR* adasAlgoName, HiAdasCapability* capability)
{
    HI_APPCOMM_CHECK_POINTER(adasAlgoName, HI_VIDEOANALYSIS_ADAS_EINVAL);
    HI_APPCOMM_CHECK_POINTER(capability, HI_VIDEOANALYSIS_ADAS_EINVAL);
    VIDEOANALYSIS_ADAS_RETURN_IF_NOT_INIT();

    HI_S32 ret = HI_AISERVICE_ADAS_GetCapability(adasAlgoName, capability);
    if (ret != HI_SUCCESS) {
        MLOGE("HI_AISERVICE_ADAS_GetCapability failed(%d)\n", ret);
        return HI_FAILURE;
    }

    return HI_SUCCESS;
}

static HI_S32 VIDEOANALYSIS_AdasGenerateAlgCfg(const HI_VIDEOANALYSIS_AdasVideoProcessTaskCfg *adasVideoProcessTaskCfg,
    HiAdasCreatePara *createPara)
{
    HI_S32 ret = memcpy_s(createPara->algoName, HI_ADAS_MAX_NAME_LEN,
        adasVideoProcessTaskCfg->algoName, HI_ADAS_MAX_NAME_LEN);
    if (ret != EOK) {
        MLOGE("memcpy_s failed\n");
        return HI_FAILURE;
    }

    createPara->initAlgo.modelPath = adasVideoProcessTaskCfg->modelPath;
    createPara->caliCallback = VIDEOANALYSIS_AdasCalibrateCallback;
    createPara->eventCallback = VIDEOANALYSIS_AdasEventCallback;
    createPara->initAlgo.capMask = adasVideoProcessTaskCfg->capMask;
    createPara->initAlgo.camAttr.camFocusLength = 0;
    createPara->initAlgo.camAttr.horizontalPixelLength = 0;
    createPara->initAlgo.camAttr.verticalPixelLength = 0;
    createPara->initAlgo.caliAttr.isCalibrated = adasVideoProcessTaskCfg->caliAttr.isCalibrated;
    createPara->initAlgo.caliAttr.vanishPoint.x = adasVideoProcessTaskCfg->caliAttr.vanishPoint.x;
    createPara->initAlgo.caliAttr.vanishPoint.y = adasVideoProcessTaskCfg->caliAttr.vanishPoint.y;
    createPara->initAlgo.allocCallback = VIDEOANALYSIS_AdasAlgoMemAlloc;
    createPara->initAlgo.flushCallback = VIDEOANALYSIS_AdasAlgoMemFlush;
    createPara->initAlgo.freeCallback = VIDEOANALYSIS_AdasAlgoMemFree;

    MLOGI("create, cali: isCalibrated:%d, vanishPoint(%d, %d)\n", createPara->initAlgo.caliAttr.isCalibrated,
        createPara->initAlgo.caliAttr.vanishPoint.x, createPara->initAlgo.caliAttr.vanishPoint.y);
    return HI_SUCCESS;
}

HI_S32 HI_VIDEOANALYSIS_CreateAdasTask(HI_HANDLE *adasTaskHdl,
    const HI_VIDEOANALYSIS_AdasVideoProcessTaskCfg *adasVideoProcessTaskCfg,
    HI_VIDEOANALYSIS_AdasTaskResultProcCb resultCb)
{
    HI_APPCOMM_CHECK_POINTER(adasTaskHdl, HI_VIDEOANALYSIS_ADAS_EINVAL);
    HI_APPCOMM_CHECK_POINTER(adasVideoProcessTaskCfg, HI_VIDEOANALYSIS_ADAS_EINVAL);

    if (adasVideoProcessTaskCfg->frameRate <= 0) {
        MLOGE("frameRate err\n");
        return HI_FAILURE;
    }

    VIDEOANALYSIS_ADAS_RETURN_IF_NOT_INIT();

    HI_MUTEX_LOCK(g_adasCtx.taskCtxMutex);
    HI_HANDLE taskHdl;
    HI_S32 ret = VIDEOANALYSIS_GetTaskHdl(&g_adasCtx, &taskHdl);
    if (ret != HI_SUCCESS) {
        MLOGE("task reach max number(%d)\n", HI_VIDEOANALYSIS_ADAS_TASK_NUM_MAX);
        HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
        return HI_FAILURE;
    }

    HiAdasCreatePara createPara;
    memset(&createPara, 0, sizeof(HiAdasCreatePara));
    ret = VIDEOANALYSIS_AdasGenerateAlgCfg(adasVideoProcessTaskCfg, &createPara);
    if (ret != HI_SUCCESS) {
        MLOGE("get alg cfg failed\n");
        HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
        return HI_FAILURE;
    }

    VIDEOANALYSIS_AdasTaskCtx *adasTaskCtx = &g_adasCtx.adasTaskCtx[taskHdl];
    adasTaskCtx->isCalibrated = adasVideoProcessTaskCfg->caliAttr.isCalibrated;
    ret = HI_AISERVICE_ADAS_Create(&adasTaskCtx->algHdl, &createPara);
    if (ret != HI_SUCCESS) {
        MLOGE("create adasAlg task failed(%d)\n", ret);
        HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
        return HI_FAILURE;
    }

    HI_VIDEOPROCESS_TaskCfg videoProcessTaskCfg;
    memset(&videoProcessTaskCfg, 0, sizeof(HI_VIDEOPROCESS_TaskCfg));
    VIDEOANALYSIS_AdasGenerateVideoProcessTaskCfg(adasTaskCtx, adasVideoProcessTaskCfg, &videoProcessTaskCfg);
    ret = HI_VIDEOPROCESS_CreateTask(&videoProcessTaskCfg, &adasTaskCtx->taskHdl);
    if (ret != HI_SUCCESS) {
        MLOGE("create video process task failed(%d)\n", ret);
        HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
        return HI_FAILURE;
    }

    adasTaskCtx->isUsed = HI_TRUE;
    adasTaskCtx->resultCb = resultCb;
    *adasTaskHdl = taskHdl;

    HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
    return HI_SUCCESS;
}

HI_S32 HI_VIDEOANALYSIS_DestroyAdasTask(HI_HANDLE adasTaskHdl)
{
    HI_APPCOMM_CHECK_POINTER((adasTaskHdl < HI_VIDEOANALYSIS_ADAS_TASK_NUM_MAX), HI_VIDEOANALYSIS_ADAS_EINVAL);
    VIDEOANALYSIS_ADAS_RETURN_IF_NOT_INIT();

    HI_MUTEX_LOCK(g_adasCtx.taskCtxMutex);
    VIDEOANALYSIS_AdasTaskCtx *adasTaskCtx = &g_adasCtx.adasTaskCtx[adasTaskHdl];

    HI_S32 ret = HI_VIDEOPROCESS_DestroyTask(adasTaskCtx->taskHdl);
    if (ret != HI_SUCCESS) {
        MLOGE("destroy video process task failed(%d)\n", ret);
        HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
        return HI_FAILURE;
    }

    ret = HI_AISERVICE_ADAS_Destroy(adasTaskCtx->algHdl);
    if (ret != HI_SUCCESS) {
        MLOGE("destroy adasAlg task failed(%d)\n", ret);
        HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
        return HI_FAILURE;
    }

    adasTaskCtx->algHdl = 0;
    adasTaskCtx->taskHdl = 0;
    adasTaskCtx->isUsed = HI_FALSE;
    adasTaskCtx->resultCb = HI_NULL;
    HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
    return HI_SUCCESS;
}

HI_S32 HI_VIDEOANALYSIS_StartAdasTask(HI_HANDLE adasTaskHdl)
{
    VIDEOANALYSIS_ADAS_RETURN_IF_NOT_INIT();

    HI_MUTEX_LOCK(g_adasCtx.taskCtxMutex);
    VIDEOANALYSIS_AdasTaskCtx *adasTaskCtx = &g_adasCtx.adasTaskCtx[adasTaskHdl];

    HI_S32 ret = HI_VIDEOPROCESS_StartTask(adasTaskCtx->taskHdl);
    if (ret != HI_SUCCESS) {
        MLOGE("start video process task failed(%d)\n", ret);
        HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
        return HI_FAILURE;
    }
    HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
    return HI_SUCCESS;
}

HI_S32 HI_VIDEOANALYSIS_StopAdasTask(HI_HANDLE adasTaskHdl)
{
    VIDEOANALYSIS_ADAS_RETURN_IF_NOT_INIT();

    HI_MUTEX_LOCK(g_adasCtx.taskCtxMutex);
    VIDEOANALYSIS_AdasTaskCtx *adasTaskCtx = &g_adasCtx.adasTaskCtx[adasTaskHdl];

    HI_S32 ret = HI_VIDEOPROCESS_StopTask(adasTaskCtx->taskHdl);
    if (ret != HI_SUCCESS) {
        MLOGE("stop video process task failed(%d)\n", ret);
        HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
        return HI_FAILURE;
    }
    HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
    return HI_SUCCESS;
}

HI_S32 HI_VIDEOANALYSIS_SetAdasTaskAttr(HI_HANDLE adasTaskHdl, HiAdasAttrType type, const HiAdasAttr* attr)
{
    HI_APPCOMM_CHECK_POINTER(attr, HI_VIDEOANALYSIS_ADAS_EINVAL);
    HI_APPCOMM_CHECK_EXPR_WITH_ERRINFO((type >= HI_ADAS_ATTR_SLI_ENABLE && type < HI_ADAS_ATTR_BUTT),
        HI_VIDEOANALYSIS_ADAS_EINVAL, "type scope err");
    VIDEOANALYSIS_ADAS_RETURN_IF_NOT_INIT();

    HI_MUTEX_LOCK(g_adasCtx.taskCtxMutex);
    VIDEOANALYSIS_AdasTaskCtx *adasTaskCtx = &g_adasCtx.adasTaskCtx[adasTaskHdl];

    HI_S32 ret = HI_AISERVICE_ADAS_SetAttr(adasTaskCtx->algHdl, type, attr);
    if (ret != HI_SUCCESS) {
        MLOGE("HI_AISERVICE_ADAS_GetAttr failed(%d)\n", ret);
        HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
        return HI_FAILURE;
    }

    HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
    return HI_SUCCESS;
}

HI_S32 HI_VIDEOANALYSIS_GetAdasTaskAttr(HI_HANDLE adasTaskHdl, HiAdasAttrType type, HiAdasAttr* attr)
{
    HI_APPCOMM_CHECK_POINTER(attr, HI_VIDEOANALYSIS_ADAS_EINVAL);
    HI_APPCOMM_CHECK_EXPR_WITH_ERRINFO((type >= HI_ADAS_ATTR_SLI_ENABLE && type < HI_ADAS_ATTR_BUTT),
        HI_VIDEOANALYSIS_ADAS_EINVAL, "type scope err");
    VIDEOANALYSIS_ADAS_RETURN_IF_NOT_INIT();

    HI_MUTEX_LOCK(g_adasCtx.taskCtxMutex);
    VIDEOANALYSIS_AdasTaskCtx *adasTaskCtx = &g_adasCtx.adasTaskCtx[adasTaskHdl];

    HI_S32 ret = HI_AISERVICE_ADAS_GetAttr(adasTaskCtx->algHdl, type, attr);
    if (ret != HI_SUCCESS) {
        MLOGE("HI_AISERVICE_ADAS_GetAttr failed(%d)\n", ret);
        HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
        return HI_FAILURE;
    }

    HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
    return HI_SUCCESS;
}

HI_S32 HI_VIDEOANALYSIS_InvokeAdasTaskCmd(HI_HANDLE adasTaskHdl, HI_U32 cmd, const HiAdasCmdPara* cmdPara)
{
    HI_APPCOMM_CHECK_POINTER(cmdPara, HI_VIDEOANALYSIS_ADAS_EINVAL);
    VIDEOANALYSIS_ADAS_RETURN_IF_NOT_INIT();

    HI_MUTEX_LOCK(g_adasCtx.taskCtxMutex);
    VIDEOANALYSIS_AdasTaskCtx *adasTaskCtx = &g_adasCtx.adasTaskCtx[adasTaskHdl];

    HI_S32 ret = HI_AISERVICE_ADAS_Invoke(adasTaskCtx->algHdl, cmd, cmdPara);
    if (ret != HI_SUCCESS) {
        MLOGE("HI_AISERVICE_ADAS_Invoke failed(%d)\n", ret);
        HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
        return HI_FAILURE;
    }

    HI_MUTEX_UNLOCK(g_adasCtx.taskCtxMutex);
    return HI_SUCCESS;
}

HI_S32 HI_VIDEOANALYSIS_DeinitAdasService(HI_VOID)
{
    if (!g_adasCtx.isInitialized) {
        MLOGW("adas service not init!\n");
        return HI_VIDEOANALYSIS_ADAS_ENOINIT;
    }

    HI_S32 ret = HI_AISERVICE_ADAS_Deinit();
    HI_APPCOMM_CHECK_RETURN(ret, ret);

    g_adasCtx.isInitialized = HI_FALSE;
    return HI_SUCCESS;
}

HI_S32 HI_VIDEOANALYSIS_RegisterEvent(HI_VOID)
{
    HI_S32 ret = HI_EVTHUB_Register(HI_EVENT_VIDEOANALYSIS_ADAS_CALIBRATION);
    HI_APPCOMM_CHECK_RETURN(ret, ret);

    ret = HI_EVTHUB_Register(HI_EVENT_VIDEOANALYSIS_ADAS_RESULT_PER_IMAGE);
    HI_APPCOMM_CHECK_RETURN(ret, ret);

    ret = HI_EVTHUB_Register(HI_EVENT_VIDEOANALYSIS_ADAS_ERROR);
    HI_APPCOMM_CHECK_RETURN(ret, ret);
    return ret;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
